﻿using Basic.FormExtendService;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.UserForm.Model;
using Basic.FormRemoteModel.UserRecord.Model;
using Basic.HrRemoteModel.DicItem.Model;
using Basic.UserFormService.Calculate.Interface;
using Basic.UserFormService.Calculate.Model;
using Basic.UserFormService.Interface;
using Basic.UserFormService.Model;
using Flee.PublicTypes;
using WeDonekRpc.Helper;

namespace Basic.UserFormService.Calculate
{
    internal class UserFormCalculate : IUserFormCalculate
    {
        private readonly IUserFormFormulaService _FormBody;
        private readonly IDictService _Dict;
        public UserFormCalculate ( IUserFormFormulaService formBody, IDictService dict )
        {
            this._Dict = dict;
            this._FormBody = formBody;
        }
        private Dictionary<long, RecordRow[]> _Records;
        private readonly List<CalculateResult> _Result = new List<CalculateResult>();
        private Dictionary<long, DicItem[]> _DicName;
        private FormFormulaStruct _Form;
        public List<CalculateResult> Calculate ( long formId, CalculateArg arg )
        {
            this._Form = this._FormBody.Get(formId);
            ColFormula[] formula = this._Form.Formula.FindAll(a => arg.ColId.Contains(a.ColId));
            if ( formula.IsNull() )
            {
                return null;
            }
            this._Records = arg.Record.ToDictionary(a => a.TableId, a => a.Rows);
            this._DicName = this._Dict.GetItemNames(this._Form.DicId, this._Form.TreeDicId);
            formula.ForEach(c =>
            {
                FormTableType tableType = this._Form.TableType[c.TableId];
                if ( tableType == FormTableType.单一表单 )
                {
                    object res = this._Calculate(c);
                    this._Result.Add(new CalculateResult
                    {
                        RowId = 1,
                        TableId = c.TableId,
                        TableType = tableType,
                        ColId = c.ColId,
                        Name = c.Name,
                        Val = res
                    });
                }
                else if ( arg.RowId.TryGetValue(c.TableId, out int[] rowId) )
                {
                    ExpressionContext exp = CalculateLinq.Clone();
                    if ( !c.VarCol.IsNull() )
                    {
                        if ( !this._InitVal(c.VarCol, exp) )
                        {
                            return;
                        }
                    }
                    rowId.ForEach(( id, i ) =>
                    {
                        object res = this._Calculate(c, exp, i);
                        this._Result.Add(new CalculateResult
                        {
                            RowId = id,
                            TableId = c.TableId,
                            ColId = c.ColId,
                            TableType = tableType,
                            Name = c.Name,
                            Val = res
                        });
                    });
                }
            });

            return this._Result;
        }

        private object _Calculate ( ColFormula formula )
        {
            ExpressionContext exp = CalculateLinq.Clone();
            if ( !formula.VarCol.IsNull() )
            {
                if ( !this._InitVal(formula.VarCol, exp) )
                {
                    return null;
                }
            }
            using ( CurState state = CalculateLinq.SetCurrentState(null) )
            {
                IDynamicExpression expre = exp.CompileDynamic(formula.Formula);
                return expre.Evaluate();
            }
        }
        private object _Calculate ( ColFormula formula, ExpressionContext exp, int index )
        {
            using ( CurState state = CalculateLinq.SetCurrentState(index) )
            {
                IDynamicExpression expre = exp.CompileDynamic(formula.Formula);
                return expre.Evaluate();
            }
        }
        private bool _InitVal ( ColFormulaVar[] vars, ExpressionContext exp )
        {
            return vars.TrueForAll(a =>
            {
                if ( !this._Records.TryGetValue(a.TableId, out RecordRow[] rows) || rows.IsNull() )
                {
                    return false;
                }
                FormTableType tableType = this._Form.TableType[a.TableId];
                if ( tableType == FormTableType.单一表单 )
                {
                    if ( rows[0].Column.TryGetValue(a.Name, out object val) )
                    {
                        exp.Variables[a.Key] = this._FormatValue(val, a);
                        return true;
                    }
                    return false;
                }
                else
                {
                    object[] datas = rows.ConvertAll(c => c.Column.GetValueOrDefault(a.Name));
                    if ( datas.IsNull() )
                    {
                        return false;
                    }
                    exp.Variables[a.Key] = this._FormatValue(datas, a);
                    return true;
                }
            });
        }
        private object[] _FormatValue ( object[] value, ColFormulaVar col )
        {
            if ( col.FuncType == DataFuncType.树形字典 || col.FuncType == DataFuncType.字典项 )
            {
                return value.ConvertAll<object, object>(a => new RecordVal
                {
                    value = a,
                    dataType = col.DataType,
                    funcType = col.FuncType,
                    dicItem = this._DicName[col.DicId.Value]
                });
            }
            else if ( col.FuncType == DataFuncType.选项值 )
            {
                return value.ConvertAll<object, object>(a => new RecordVal
                {
                    value = a,
                    dataType = col.DataType,
                    funcType = col.FuncType,
                    items = this._Form.Items[col.ColId]
                });
            }
            return value;
        }
        private object _FormatValue ( object value, ColFormulaVar col )
        {
            if ( col.FuncType == DataFuncType.树形字典 || col.FuncType == DataFuncType.字典项 )
            {
                return new RecordVal
                {
                    value = value,
                    dataType = col.DataType,
                    funcType = col.FuncType,
                    dicItem = this._DicName[col.DicId.Value]
                };
            }
            else if ( col.FuncType == DataFuncType.选项值 )
            {
                return new RecordVal
                {
                    value = value,
                    dataType = col.DataType,
                    funcType = col.FuncType,
                    items = this._Form.Items[col.ColId]
                };
            }
            return value;
        }
    }
}
